package com.zy.gateway.service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zy.gateway.data.CustomRoute;
import com.zy.gateway.data.entity.RouteInfo;
import com.zy.gateway.data.query.RouteInfoQuery;
import com.zy.gateway.mapper.RouteInfoMapper;
import com.zy.gateway.service.RouteInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class RouteInfoServiceImpl extends ServiceImpl<RouteInfoMapper, RouteInfo> implements RouteInfoService, ApplicationEventPublisherAware, ApplicationRunner {

    //通过构造方法进行注入，此处通过跟踪代码，RouteDefinitionWriter的实现类是基于内存的，非redis的
    private ApplicationEventPublisher publisher;

    private final RouteDefinitionWriter routeDefinitionWriter;

    public RouteInfoServiceImpl(RouteDefinitionWriter routeDefinitionWriter) {
        this.routeDefinitionWriter = routeDefinitionWriter;
    }

    public List<RouteInfo> selectList() {
        return baseMapper.list(new RouteInfoQuery(), RouteInfoQuery.class);
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("----------加载路由信息Start---------");
        List<RouteInfo> list = selectList();
        if (list != null && !list.isEmpty()) {
            for (RouteInfo info : list) {
                System.out.println("----------加载路由“" + info.getRouteName() + "”---------");
//                definition = convertCustomRouteDefinition(info);
                RouteDefinition routedefinition = convert(info);

                routeDefinitionWriter.save(Mono.just(routedefinition)).subscribe();
            }
            publishRouteEvent();
        }
        System.out.println("----------加载路由信息End---------");
    }

    private void publishRouteEvent() {
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    /**
     * 转换为自定义路由
     *
     * @param info 路由持久化对象
     * @return 自定义路由
     */
    private CustomRoute convertCustomRouteDefinition(RouteInfo info) {
        CustomRoute customRoute = new CustomRoute();
        // customRoute.setDescription(info.getDescription());
        customRoute.setFilters(JSON.parseArray(info.getFilters(), FilterDefinition.class));
        customRoute.setId(info.getId());
        customRoute.setName(info.getRouteName());
        customRoute.setOrder(info.getOrder());
        customRoute.setPredicateDefinitions(JSON.parseArray(info.getPredicates(), CustomRoute.class));
        customRoute.setUrl(info.getUrl());
        return customRoute;
    }

    /**
     * 把自定义请求模型转换为RouteDefinition
     *
     * @param info
     * @return
     */
    private RouteDefinition convert(RouteInfo info) {
        RouteDefinition definition = new RouteDefinition();
        definition.setId(String.valueOf(info.getId()));
        definition.setOrder(info.getOrder());
        //设置断言
        JSONArray array = JSON.parseArray(info.getPredicates());
        List<PredicateDefinition> predicateDefinitions = array.stream()
                .distinct().map(predicateInfo -> {
                    Map<String, String> map = JSON.parseObject(JSONObject.toJSONString(predicateInfo), Map.class);
                    PredicateDefinition predicate = new PredicateDefinition();
                    for (String key : map.keySet()) {
                        predicate.setArgs(map);
                        predicate.setName(key);
                    }
                    return predicate;
                }).collect(Collectors.toList());
        definition.setPredicates(predicateDefinitions);

//        if (form.getFilters() != null) {
//            // 设置过滤
//            List<FilterDefinition> filterList = info.getFilters().stream().distinct().map(x -> {
//                FilterDefinition filter = new FilterDefinition();
//                filter.setName(x.getName());
//                filter.setArgs(x.getArgs());
//                return filter;
//            }).collect(Collectors.toList());
//            definition.setFilters(filterList);
//        }
        // 设置URI,判断是否进行负载均衡
        URI uri;
        if (info.getUrl().startsWith("http")) {
            uri = UriComponentsBuilder.fromHttpUrl(info.getUrl()).build().toUri();
        } else {
            uri = URI.create(info.getUrl());
        }
        definition.setUri(uri);
        return definition;
    }
}
